#!/usr/bin/env python
#coding:utf-8

import wx
import numpy as np
import wx.xrc
from Debug import debug, error
import Database
from datetime import datetime
from sqlobject import *
import codecs
import os

###########################################################################
## Class CalibWindow
###########################################################################

class CalibWindow ( wx.Frame ):
    
    def __init__( self, parent ):
        self.errorflag = False
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"传感器标定窗口", pos = wx.DefaultPosition, size = wx.Size( 800,600 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
        
        self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
        
        bSizer28 = wx.BoxSizer( wx.VERTICAL )
        
        self.m_panel19 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        bSizer29 = wx.BoxSizer( wx.VERTICAL )
        
        self.m_staticText23 = wx.StaticText( self.m_panel19, wx.ID_ANY, u"传感器实时PV值：", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText23.Wrap( -1 )
        bSizer29.Add( self.m_staticText23, 0, wx.ALL, 5 )
        
        bSizer52 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_lcPVS = wx.ListCtrl( self.m_panel19, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_HRULES|wx.LC_REPORT|wx.LC_VRULES )
        bSizer52.Add( self.m_lcPVS, 1, wx.ALL|wx.EXPAND, 5 )
        
        self.m_textCtrl18 = wx.TextCtrl( self.m_panel19, wx.ID_ANY, u"如果出现红色提示 ，\n表示校准样架可能没有放置就位，请人工纠正", wx.DefaultPosition, wx.Size( 200,-1 ), wx.TE_MULTILINE|wx.TE_READONLY )
        self.m_textCtrl18.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) )
        self.m_textCtrl18.SetForegroundColour( wx.Colour( 255, 0, 0 ) )
        
        bSizer52.Add( self.m_textCtrl18, 0, wx.ALL|wx.EXPAND, 5 )
        
        
        bSizer29.Add( bSizer52, 1, wx.EXPAND, 5 )
        
        self.m_staticText25 = wx.StaticText( self.m_panel19, wx.ID_ANY, u"标定值：", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText25.Wrap( -1 )
        bSizer29.Add( self.m_staticText25, 0, wx.ALL, 5 )
        
        self.m_lcCalibPVS = wx.ListCtrl( self.m_panel19, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_HRULES|wx.LC_NO_HEADER|wx.LC_REPORT|wx.LC_VRULES )
        bSizer29.Add( self.m_lcCalibPVS, 1, wx.ALL|wx.EXPAND, 5 )
        
        self.m_staticText24 = wx.StaticText( self.m_panel19, wx.ID_ANY, u"标定进度：", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText24.Wrap( -1 )
        bSizer29.Add( self.m_staticText24, 0, wx.ALL, 5 )
        
        self.m_slider = wx.Gauge( self.m_panel19, wx.ID_ANY, 50, wx.DefaultPosition, wx.DefaultSize, wx.GA_HORIZONTAL )
        self.m_slider.SetValue( 0 ) 
        bSizer29.Add( self.m_slider, 0, wx.ALL|wx.EXPAND, 5 )
        
        self.m_staticline9 = wx.StaticLine( self.m_panel19, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
        bSizer29.Add( self.m_staticline9, 0, wx.EXPAND |wx.ALL, 5 )
        
        bSizer30 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_btnReCalib = wx.Button( self.m_panel19, wx.ID_ANY, u"标定...", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer30.Add( self.m_btnReCalib, 0, wx.ALL, 5 )
        
        self.m_staticText26 = wx.StaticText( self.m_panel19, wx.ID_ANY, u"!!!标定前请将传感器推送到校准平面", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText26.Wrap( -1 )
        self.m_staticText26.SetFont( wx.Font( 14, 74, 90, 92, False, "Tahoma" ) )
        self.m_staticText26.SetForegroundColour( wx.Colour( 255, 0, 0 ) )
        
        bSizer30.Add( self.m_staticText26, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        
        
        bSizer30.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
        
        self.m_btnClose = wx.Button( self.m_panel19, wx.ID_OK, u"关闭", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer30.Add( self.m_btnClose, 0, wx.ALL, 5 )
        
        
        bSizer29.Add( bSizer30, 0, wx.EXPAND, 5 )
        
        
        self.m_panel19.SetSizer( bSizer29 )
        self.m_panel19.Layout()
        bSizer29.Fit( self.m_panel19 )
        bSizer28.Add( self.m_panel19, 1, wx.EXPAND, 5 )
        
        
        self.SetSizer( bSizer28 )
        self.Layout()
        
        self.Centre( wx.BOTH )
        
        # Connect Events
        self.m_btnClose.Bind( wx.EVT_BUTTON, self.OnClose )
        self.m_btnReCalib.Bind( wx.EVT_BUTTON, self.OnReCalib)
        self.Bind(wx.EVT_TIMER, self.TimerHandler)
        self.timer = wx.Timer(self)
        
        self.pvbuffer = []
        self.timer.Start(100)
        self.flag = False
        self.error = False
        
        self.Init()
        
    def Init(self):
        self.m_lcPVS.InsertColumn(0, u"传感器")
        self.m_lcPVS.InsertColumn(1, u"PV值")
        self.m_lcPVS.InsertColumn(2, u"提示", width = 200)
        self.m_lcPVS.InsertColumn(3, u"最小值")
        self.m_lcPVS.InsertColumn(4, u"最大值")
        for i in range(6):
            self.m_lcPVS.InsertStringItem(i, u"传感器%d" % (i+1))
            
        self.m_lcCalibPVS.InsertColumn(0, "item")
        self.m_lcCalibPVS.InsertColumn(1, "value")
        for i in range(6):
            self.m_lcCalibPVS.InsertStringItem(i, u"传感器%d" % (i+1))
        
        lzpv = app.domain.GetLeftZeroPV()
        rzpv = app.domain.GetRightZeroPV()
        zpv = list(lzpv) + list(rzpv)
        self.zpv = zpv
        for i in range(6):
            self.m_lcCalibPVS.SetStringItem(i, 1, '%.4f' % zpv[i])
            
        self.std_zpv = [(app.pref.left_zero_pv1_std-app.pref.left_zero_pv1_offset, app.pref.left_zero_pv1_std+app.pref.left_zero_pv1_offset),
                        (app.pref.left_zero_pv2_std-app.pref.left_zero_pv2_offset, app.pref.left_zero_pv2_std+app.pref.left_zero_pv2_offset),
                        (app.pref.left_zero_pv3_std-app.pref.left_zero_pv3_offset, app.pref.left_zero_pv3_std+app.pref.left_zero_pv3_offset),
                        (app.pref.right_zero_pv4_std-app.pref.right_zero_pv4_offset, app.pref.right_zero_pv4_std+app.pref.right_zero_pv4_offset),
                        (app.pref.right_zero_pv5_std-app.pref.right_zero_pv5_offset, app.pref.right_zero_pv5_std+app.pref.right_zero_pv5_offset),
                        (app.pref.right_zero_pv6_std-app.pref.right_zero_pv6_offset, app.pref.right_zero_pv6_std+app.pref.right_zero_pv6_offset)]
        for i in range(6):
            self.m_lcPVS.SetStringItem(i, 3, "%.3f" % self.std_zpv[i][0])
            self.m_lcPVS.SetStringItem(i, 4, "%.3f" % self.std_zpv[i][1])
    
    # Virtual event handlers, overide them in your derived class
    def OnClose( self, event ):
        self.timer.Stop()
        self.Close()
        
    def SetPvsItemColour(self, item, col):
        try:
            self.m_lcPVS.SetItemBackgroundColour(item, col)
        except:
            pass
        
    def TimerHandler(self, evt):
        self.errorflag = self.CheckSensorPos()
        
        try:
            try:
                pvs = app.domain.rs1a.M0()
            except:
                return
            
            #self.errorflag = False
            for i in range(6):
                self.m_lcPVS.SetStringItem(i, 1, '%.3fmm' % pvs[i])
                if abs(pvs[i] - self.zpv[i]) >= app.pref.max_diff_val:
                    self.errorflag = True
                    self.m_lcPVS.SetStringItem(i, 2, u"与上一次标定值相差过大")
                    self.SetPvsItemColour(i, wx.RED)
                elif pvs[i] < self.std_zpv[i][0]:
                    self.errorflag = True
                    self.m_lcPVS.SetStringItem(i, 2, u"小于标准值")
                    self.SetPvsItemColour(i, wx.RED)
                elif pvs[i] > self.std_zpv[i][1]:
                    self.errorflag = True
                    self.m_lcPVS.SetStringItem(i, 2, u"大于标准值")
                    self.SetPvsItemColour(i, wx.RED)
                else:
                    self.m_lcPVS.SetStringItem(i, 2, u"")
                    self.SetPvsItemColour(i, wx.WHITE)
            if self.flag:
                self.pvbuffer.append(pvs)
                self.m_slider.SetValue(len(self.pvbuffer) + 1)
                if len(self.pvbuffer) == 50:
                    ar = np.array(self.pvbuffer)
                    arv = np.mean(ar, 0)
                    app.pref.left_zero_pv1 = arv[0]
                    app.pref.left_zero_pv2 = arv[1]
                    app.pref.left_zero_pv3 = arv[2]
                    app.pref.right_zero_pv4 = arv[3]
                    app.pref.right_zero_pv5 = arv[4]
                    app.pref.right_zero_pv6 = arv[5]
                    app.pref.save()
                    Database.MCalibrationLog(pv1 = float(arv[0]),
                                             pv2 = float(arv[1]),
                                             pv3 = float(arv[2]),
                                             pv4 = float(arv[3]),
                                             pv5 = float(arv[4]),
                                             pv6 = float(arv[5]))
                    for i in range(6):
                        self.m_lcCalibPVS.SetStringItem(i, 1, '%.3fmm' % arv[i])
                    app.viewcon.UpdateZeroPV()
                    self.flag = False
                    self.pvbuffer = []
                    wx.MessageBox(u"标定完成")
        except:
            debug.traceback()
            
    def CheckSensorPos(self):
        try:
            v_lsensorlimit = app.condomain.v_lsensorlimit.GetValue()
            v_rsensorlimit = app.condomain.v_rsensorlimit.GetValue()
            
            if v_lsensorlimit and v_rsensorlimit:
                self.m_staticText26.SetLabel(u"左右传感器达到预定位置")
                self.m_staticText26.SetForegroundColour(wx.GREEN)
                return False
            elif v_lsensorlimit and (not v_rsensorlimit):
                self.m_staticText26.SetLabel(u"!右传感器没有达到预定位置")
                self.m_staticText26.SetForegroundColour(wx.RED)
                return True
            elif (not v_lsensorlimit) and v_rsensorlimit:
                self.m_staticText26.SetLabel(u"!左传感器没有达到预定位置")
                self.m_staticText26.SetForegroundColour(wx.RED)
                return True
            else:
                self.m_staticText26.SetLabel(u"!!左右传感器都没有达到预定位置")
                self.m_staticText26.SetForegroundColour(wx.RED)
                return True
        except:
            debug.traceback()
        return False
    
    def OnReCalib(self, evt):
        if self.errorflag:
            if wx.MessageBox(u"数值存在异常，您确定要强制校确码？", u"提示", wx.YES_NO | wx.ICON_ERROR) == wx.NO:
                return
            else:
                from UserLoginDlg import UserLoginDlg
                dlg = UserLoginDlg(self, u"再次输入用户名、密码")
                dlg.ShowModal()
                if not dlg.Success:
                    return
        
        if wx.MessageBox(u"确定需要重新标定传感器吗？", u"提示", wx.YES_NO| wx.ICON_QUESTION) == wx.YES:
            for i in range(6):
                self.m_lcCalibPVS.SetStringItem(i, 1, '')
            self.flag = True
            
class CalibLogWindow ( wx.Dialog ):
    
    def __init__( self, parent ):
        wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"标定历史记录", pos = wx.DefaultPosition, size = wx.Size( 600,-1 ), style = wx.DEFAULT_DIALOG_STYLE )
        
        self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
        
        bSizer40 = wx.BoxSizer( wx.VERTICAL )
        
        bSizer41 = wx.BoxSizer( wx.HORIZONTAL )
        
        sbSizer2 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"查询方式" ), wx.VERTICAL )
        
        bSizer10 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_rbDateQuery = wx.RadioButton( self, wx.ID_ANY, u"日期查询", wx.DefaultPosition, wx.DefaultSize, wx.RB_GROUP )
        self.m_rbDateQuery.SetValue( True ) 
        bSizer10.Add( self.m_rbDateQuery, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        
        self.m_staticline5 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_VERTICAL )
        bSizer10.Add( self.m_staticline5, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_dpBeginDate = wx.DatePickerCtrl( self, wx.ID_ANY, wx.DefaultDateTime, wx.DefaultPosition, wx.DefaultSize, wx.DP_DEFAULT )
        bSizer10.Add( self.m_dpBeginDate, 0, wx.ALL, 5 )
        
        self.m_staticText21 = wx.StaticText( self, wx.ID_ANY, u"到", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_staticText21.Wrap( -1 )
        bSizer10.Add( self.m_staticText21, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        
        self.m_dpEndDate = wx.DatePickerCtrl( self, wx.ID_ANY, wx.DefaultDateTime, wx.DefaultPosition, wx.DefaultSize, wx.DP_DEFAULT )
        bSizer10.Add( self.m_dpEndDate, 0, wx.ALL, 5 )
        
        sbSizer2.Add( bSizer10, 0, wx.EXPAND, 5 )
        
        bSizer11 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_rbLastQuery = wx.RadioButton( self, wx.ID_ANY, u"最近记录", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer11.Add( self.m_rbLastQuery, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        
        self.m_staticline6 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_VERTICAL )
        bSizer11.Add( self.m_staticline6, 0, wx.EXPAND |wx.ALL, 5 )
        
        m_cbLastCountChoices = [ u"1", u"2", u"3", u"4", u"5", u"6", u"7", u"8", u"9", u"10", u"15", u"20", u"30" ]
        self.m_cbLastCount = wx.ComboBox( self, wx.ID_ANY, u"1", wx.DefaultPosition, wx.Size( 100,-1 ), m_cbLastCountChoices, 0 )
        bSizer11.Add( self.m_cbLastCount, 0, wx.ALL, 5 )
        
        sbSizer2.Add( bSizer11, 0, wx.EXPAND, 5 )
        
        bSizer41.Add( sbSizer2, 1, wx.ALL, 5 )
        
        self.m_btnQuery = wx.Button( self, wx.ID_ANY, u"查询", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer41.Add( self.m_btnQuery, 0, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 )
        
        bSizer40.Add( bSizer41, 1, wx.EXPAND, 5 )
        
        self.m_staticline20 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
        bSizer40.Add( self.m_staticline20, 0, wx.EXPAND |wx.ALL, 5 )
        
        self.m_lcList = wx.ListCtrl( self, wx.ID_ANY, wx.DefaultPosition, wx.Size( -1,300 ), wx.LC_HRULES|wx.LC_REPORT|wx.LC_VRULES )
        bSizer40.Add( self.m_lcList, 0, wx.ALL|wx.EXPAND, 5 )
        
        self.m_staticline21 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
        bSizer40.Add( self.m_staticline21, 0, wx.EXPAND |wx.ALL, 5 )
        
        bSizer48 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.m_btnExport = wx.Button( self, wx.ID_ANY, u"导出...", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer48.Add( self.m_btnExport, 0, wx.ALL, 5 )
        
        
        bSizer48.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
        
        self.m_btnClose = wx.Button( self, wx.ID_OK, u"关闭", wx.DefaultPosition, wx.DefaultSize, 0 )
        self.m_btnClose.SetDefault() 
        bSizer48.Add( self.m_btnClose, 0, wx.ALL, 5 )
        
        bSizer40.Add( bSizer48, 0, wx.EXPAND, 5 )
        
        self.SetSizer( bSizer40 )
        self.Layout()
        
        self.Centre( wx.BOTH )
        
        # Connect Events
        self.m_btnQuery.Bind( wx.EVT_BUTTON, self.OnQuery )
        self.m_btnExport.Bind( wx.EVT_BUTTON, self.OnExport )
        
        self.Init()
    
    # Virtual event handlers, overide them in your derived class
    def OnQuery( self, event ):
        if self.m_rbDateQuery.GetValue():
            begindate = self.m_dpBeginDate.GetValue()
            enddate = self.m_dpEndDate.GetValue()
            begindate = datetime(begindate.GetYear(), 
                                      begindate.GetMonth() + 1,
                                      begindate.GetDay(),
                                      0,0,0)
            enddate = datetime(enddate.GetYear(), 
                                      enddate.GetMonth() + 1,
                                      enddate.GetDay(),
                                      23,59,59)
            r = Database.MCalibrationLog.select(AND(Database.MCalibrationLog.q.createtime > begindate, Database.MCalibrationLog.q.createtime < enddate),
                           orderBy = DESC(Database.MCalibrationLog.q.createtime))
            self.UpdateList(r)
        elif self.m_rbLastQuery.GetValue():
            try:
                cnt = int(self.m_cbLastCount.GetValue())
            except:
                wx.MessageBox(u"请输入正确的数据")
                return
            r = Database.MCalibrationLog.select(orderBy = DESC(Database.MCalibrationLog.q.createtime))
            self.UpdateList(r[:cnt])
    
    def OnExport( self, event ):
        wildcard = "CSV file (*.csv)|*.csv|" \
           "All files (*.*)|*.*"
        
        dlg = wx.FileDialog(
            self, message=u"导出 ...", defaultDir=os.path.join(os.getcwd(), 'export'), 
            defaultFile=datetime.now().strftime("%Y%m%d%H%M%S")+'.csv', wildcard=wildcard, style=wx.SAVE
            )
        if dlg.ShowModal() == wx.ID_OK:
            import csv
            writer = csv.writer(codecs.open(dlg.GetPath(), 'wb', 'utf-8'))
            rowcnt = self.m_lcList.GetItemCount()
            colcnt = self.m_lcList.GetColumnCount()
            
            vals = []
            for j in range(colcnt):
                vals.append(self.m_lcList.GetColumn(j).GetText())
            writer.writerow(vals)
            for i in range(rowcnt):
                vals = []
                for j in range(colcnt):
                    vals.append(self.m_lcList.GetItem(i, j).GetText())
                writer.writerow(vals)
                
    def Init(self):
        self.m_lcList.InsertColumn(0, u'ID')
        self.m_lcList.InsertColumn(1, u'标定时间')
        self.m_lcList.InsertColumn(2, u'PV1')
        self.m_lcList.InsertColumn(3, u'PV2')
        self.m_lcList.InsertColumn(4, u'PV3')
        self.m_lcList.InsertColumn(5, u'PV4')
        self.m_lcList.InsertColumn(6, u'PV5')
        self.m_lcList.InsertColumn(7, u'PV6')
        
    def UpdateList(self, record):
        self.m_lcList.DeleteAllItems()
        item = 0
        for i, vals in enumerate(record):
            self.m_lcList.InsertStringItem(item, str(vals.id))
            self.m_lcList.SetStringItem(item, 1, vals.createtime.strftime("%Y-%m-%d %H:%M:%S"))
            self.m_lcList.SetStringItem(item, 2, u'%.3f' % vals.pv1)
            self.m_lcList.SetStringItem(item, 3, u'%.3f' % vals.pv2)
            self.m_lcList.SetStringItem(item, 4, u'%.3f' % vals.pv3)
            self.m_lcList.SetStringItem(item, 5, u'%.3f' % vals.pv4)
            self.m_lcList.SetStringItem(item, 6, u'%.3f' % vals.pv5)
            self.m_lcList.SetStringItem(item, 7, u'%.3f' % vals.pv6)
            item += 1
